package org.colcon.web.model;

import java.util.Date;

import org.colcon.web.model.framework.IContainer;
import org.colcon.web.model.framework.IGroup;
import org.colcon.web.model.framework.IItem;
import org.colcon.web.model.framework.ITitle;
import org.colcon.web.model.framework.IUser;

public class Model
{
	public static final String
	
		NULL = "null",
		
		ROOT = "colcon",
	
		NEWS = "news",
		USERS = "users",
		GROUPS = "groups",
		
		// groups
		CONTRIBUTOR_CONGRESS = "contributor_congress",
		GROUP_CONGRESS = "group_congress",
		USER_CONGRESS = "user_congress",
		
		// users
		ADMIN = "admin",
		
		// commands
		GET = "get",
		SET = "set",
		ADD = "add",
		REMOVE = "remove",
		OPEN = "open",
		ASSIGN = "assign",
	
		// command arguments
		CMD = "cmd",
		PATH = "path",
		TYPE = "type",
		USER = "user";
	
	private static IContainer root;
	
	private static int nextId;
	
	public static void init()
	{
		System.out.println("~ Collective Congress ~");
		System.out.println("Initializing server...");
		
		root = new Container(ROOT);
		
		nextId = 0;
		
		root.addContainer(NEWS);
		root.addContainer(USERS);
		root.addContainer(GROUPS);
		
		IGroup userCongress = new Group(USER_CONGRESS, 
				"The lower house of the Collective Congress government, " +
				"the group for all users");
		userCongress.addParam(Group.PUBLIC, false);
		addGroup(userCongress);
		
		IGroup groupCongress = new Group(GROUP_CONGRESS, 
				"The upper house of the Collective Congress government, " +
				"the group for all group representatives");
		groupCongress.addParam(Group.PUBLIC, false);
		addGroup(groupCongress);
		
		IGroup contributorCongress = new Group(CONTRIBUTOR_CONGRESS, 
				"The executive branch of the Collective Congress government, " +
				"the group for all programmers, testers, and donors");
		contributorCongress.addParam(Group.PUBLIC, false);
		addGroup(contributorCongress);
		
		// TODO: read password from encrypted file
		IUser admin = new User(ADMIN, "danvegeto@gmail.com", "admin");
		addUser(admin);
		
		addMember(USER_CONGRESS, ADMIN);
		addMember(GROUP_CONGRESS, ADMIN);
		addMember(CONTRIBUTOR_CONGRESS, ADMIN);
		
		System.out.println("Initialization complete\n");
	}
	
	public static IItem get(String path)
	{
		if(path == null || path.length() == 0 || path.equals(ROOT))
			return root;
		
		return root.get(path);
	}

	public static boolean has(String parent, String path)
	{
		return has(parent + '/' + path);
	}
	
	public static boolean has(String path)
	{
		return get(path) != null;
	}
	
	public static boolean add(IItem item)
	{
		return add("", item);
	}
	
	public static boolean add(String parent, IItem item)
	{
		if(parent == null || !has(parent) || !get(parent).isContainer())
			return false;
		
		if(!item.hasId())
			item.setId(getNextId());
		
		//item.setParentPath(parent);
		
		return root.add(parent, item);
	}
	
	public static boolean remove(String parent, String id)
	{
		return remove(parent + '/' + id);
	}
	
	public static boolean remove(String path)
	{
		IItem item = get(path);
		
		if(item == null)
			return false;
		
		IItem parent = get(item.getParentPath());
		
		if(parent == null || !parent.isContainer())
			return false;
		
		return ((IContainer)parent).removeChild(item.getId());
	}
	
	public static IItem[] getItems(String[] paths)
	{
		IItem[] items = new IItem[paths.length];
		
		for(int i = 0; i < paths.length; i++)
			items[i] = get(paths[i]);
		
		return items;
	}
	
	public static IUser[] getUsers()
	{
		return root.getGrandChildren(USERS).toArray(new IUser[0]);
	}
	
	public static IGroup[] getGroups()
	{
		return root.getGrandChildren(GROUPS).toArray(new IGroup[0]);
	}
	
	public static IUser getUser(String id)
	{
		return (IUser) get(USERS + '/' + id);
	}
	
	public static IGroup getGroup(String id)
	{
		return (IGroup) get(GROUPS + '/' + id);
	}
	
	public static boolean hasUser(String id)
	{
		return getUser(id) != null;
	}
	
	public static boolean hasGroup(String id)
	{
		return getGroup(id) != null;
	}
	
	public static boolean addUser(IUser user)
	{
		boolean result = add(USERS, user);
		
		if(!result)
			return false;
		
		return addMember(USER_CONGRESS, user.getId());
	}
	
	public static boolean addGroup(IGroup group)
	{
		return add(GROUPS, group);
	}
	
	public static IGroup getContributorCongress()
	{
		return getGroup(CONTRIBUTOR_CONGRESS);
	}

	public static IGroup getUserCongress()
	{
		return getGroup(USER_CONGRESS);
	}

	public static IGroup getGroupCongress()
	{
		return getGroup(GROUP_CONGRESS);
	}
	
	public static String getNextId()
	{
		nextId = (nextId + 1) % (Integer.MAX_VALUE - 1);
		
		return "item" + nextId;
	}
	
	public static boolean assignTitle(String titlePath, String userId)
	{
		IItem title = get(titlePath);
		IItem user = getUser(userId);
		
		if(title == null || user == null ||
				!(title instanceof ITitle && 
						user instanceof IUser))
			return false;
		
		boolean result1 = ((ITitle) title).addHolder(userId);
		boolean result2 = ((IUser) user).addTitle(titlePath);
		
		return result1 && result2;
	}
	
	public static boolean addMember(String groupId, String userId)
	{
		return assignTitle("groups/" + groupId + "/titles/member", userId);
	}
	
	public static void setDate(IItem item)
	{
		item.setDate(new Date());
	}
	
	public static Date addToDate(Date date, int days)
	{
		Date newDate = new Date();
		newDate.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
		return newDate;
	}
	
	public static String getContainerPath(String id)
	{
		return ROOT + '/' + id; 
	}
	
	public static String getUserContainerPath()
	{
		return getContainerPath(USERS);
	}
	
	public static String getGroupContainerPath()
	{
		return getContainerPath(GROUPS);
	}
	
	public static String getUserPath(String id)
	{
		return getUserContainerPath() + '/' + id;
	}
	
	public static String getGroupPath(String id)
	{
		return getGroupContainerPath() + '/' + id;
	}
	
	public static String getTitleContainer(String group)
	{
		return getGroupPath(group) + '/' + Group.TITLES;
	}
	
	public static String getTitlePath(String group, String title)
	{
		return getTitleContainer(group) + '/' + title;
	}
	
	public static String formatId(String id)
	{
		String str = id.toLowerCase();
		
		str.replaceAll(" ", "_");
		
		return str;
	}
	
	public static String parseId(String path)
	{
		if(path == null || path.length() == 0)
			return null;
		
		String[] array = path.split("/");
		
		if(array == null || array.length == 0)
			return null;
		
		return array[array.length - 1];
	}
	
	public static String parseGroup(String path)
	{
		if(path == null || path.length() == 0)
			return null;
		
		String[] array = path.split("/");
		
		if(array == null || array.length < 2)
			return null;
		
		if(!array[0].equals(Model.GROUPS))
			return null;
		
		return array[1];
	}
	
	public static String getTitleString(String path)
	{
		return Model.parseId(path) + " of " + Model.parseGroup(path);
	}
}
